package com.favccxx.search.domain.calcite;

import com.favccxx.search.domain.calcite.driver.AbstractCalciteDriver;
import com.favccxx.search.domain.calcite.driver.CalciteJdbcDriver;
import com.favccxx.search.domain.datasource.datasource.AbstractDataSource;
import com.favccxx.search.domain.datasource.datasource.AbstractDataSourceRepo;
import com.favccxx.search.domain.datasource.datasource.JdbcDataSource;
import com.favccxx.search.infrastructure.constant.CalciteConstants;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Set;

/**
 * @author favccxx
 */
@Service
public class CalciteModelService {

    @Autowired
    AbstractDataSourceRepo dataSourceRepo;


    /**
     * Get calcite connect model
     *
     * @return
     * @Example {
     * "version": "1.0",
     * "defaultSchema": "MySQLDev",
     * "schemas": [
     * {
     * "type": "custom",
     * "factory": "org.apache.calcite.adapter.jdbc.JdbcSchema$Factory",
     * "operand": {
     * "jdbcDriver": "com.mysql.cj.jdbc.Driver",
     * "jdbcUser": "root",
     * "jdbcUrl": "jdbc:mysql://xxx.xxx.xxx.xxx:3306/xxx?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false",
     * "jdbcSchema": "xxxx",
     * "jdbcPassword": "111111"
     * },
     * "name": "MySQLDev"
     * }
     * ]
     * }
     */
    public CalciteModel getCalciteModel() {
        CalciteModel calciteModel = new CalciteModel();
        calciteModel.setVersion(CalciteConstants.CALCITE_VERSION);
        List<AbstractDataSource> dataSourceList = dataSourceRepo.findAll();

        List<AbstractCalciteDriver> driverList = new ArrayList<AbstractCalciteDriver>();

        boolean flag = false;
        for (AbstractDataSource dataSource : dataSourceList) {
            if (!flag) {
                // Set default data source
                flag = true;
                calciteModel.setDefaultSchema(dataSource.getCode());
            }

            if (dataSource instanceof JdbcDataSource) {
                JdbcDataSource jdbcDataSource = (JdbcDataSource) dataSource;
                CalciteJdbcDriver jdbcDriver = new CalciteJdbcDriver();
                jdbcDriver.setName(dataSource.getCode());

                HashMap<String, Object> operand = new HashMap<>();
                operand.put("jdbcDriver", jdbcDataSource.getJdbcConnection().getDriver());
                operand.put("jdbcUrl", jdbcDataSource.getJdbcConnection().getUrl());
                operand.put("jdbcSchema", jdbcDataSource.getJdbcConnection().getSchema());
                operand.put("jdbcUser", jdbcDataSource.getJdbcConnection().getUsername());
                operand.put("jdbcPassword", jdbcDataSource.getJdbcConnection().getPassword());
                jdbcDriver.setOperand(operand);

                driverList.add(jdbcDriver);
            }
        }

        calciteModel.setSchemas(driverList);
        return calciteModel;
    }


    public CalciteModel getCalciteModel(Set<String> dataSourceCodes) {
        CalciteModel calciteModel = new CalciteModel();
        calciteModel.setVersion(CalciteConstants.CALCITE_VERSION);
        List<AbstractDataSource> dataSourceList = dataSourceRepo.findAll();

        List<AbstractCalciteDriver> driverList = new ArrayList<AbstractCalciteDriver>();

        boolean flag = false;
        for (String dataSourceCode : dataSourceCodes) {
            if (!flag) {
                // Set default data source
                flag = true;
                calciteModel.setDefaultSchema(dataSourceCode);
            }

            AbstractDataSource dataSource = dataSourceRepo.findByCode(dataSourceCode);

            if (dataSource instanceof JdbcDataSource) {
                JdbcDataSource jdbcDataSource = (JdbcDataSource) dataSource;
                CalciteJdbcDriver jdbcDriver = new CalciteJdbcDriver();
                jdbcDriver.setName(dataSource.getCode());

                HashMap<String, Object> operand = new HashMap<>();
                operand.put("jdbcDriver", jdbcDataSource.getJdbcConnection().getDriver());
                operand.put("jdbcUrl", jdbcDataSource.getJdbcConnection().getUrl());
                operand.put("jdbcSchema", jdbcDataSource.getJdbcConnection().getSchema());
                operand.put("jdbcUser", jdbcDataSource.getJdbcConnection().getUsername());
                operand.put("jdbcPassword", jdbcDataSource.getJdbcConnection().getPassword());
                jdbcDriver.setOperand(operand);

                driverList.add(jdbcDriver);
            }
        }

        calciteModel.setSchemas(driverList);
        return calciteModel;
    }



   /* public List<CalciteModel> getConnectionModel() {
        List<AbstractDataSource> dataSourceList = dataSourceRepo.findAll();

        List<CalciteModel> calciteModelList = new ArrayList<>();

        dataSourceList.forEach(dataSource -> {
            CalciteModel calciteModel = new CalciteModel();
            calciteModel.setVersion("1.0");
            calciteModel.setDefaultSchema(dataSource.getCode());

            if (dataSource instanceof JdbcDataSource) {
                JdbcDataSource jdbcDataSource = (JdbcDataSource) dataSource;
                CalciteJdbcDriver jdbcDriver = new CalciteJdbcDriver();
                jdbcDriver.setName(dataSource.getCode());

                HashMap<String, Object> operand = new HashMap<>();
                operand.put("jdbcDriver", jdbcDataSource.getJdbcConnection().getDriver());
                operand.put("jdbcUrl", jdbcDataSource.getJdbcConnection().getUrl());
                operand.put("jdbcSchema", jdbcDataSource.getJdbcConnection().getSchema());
                operand.put("jdbcUser", jdbcDataSource.getJdbcConnection().getUsername());
                operand.put("jdbcPassword", jdbcDataSource.getJdbcConnection().getPassword());
                jdbcDriver.setOperand(operand);

                List<CalciteDriver> drivers = new ArrayList<>();
                drivers.add(jdbcDriver);
                calciteModel.setSchemas(drivers);

                calciteModelList.add(calciteModel);

            }
        });

        return calciteModelList;
    }*/
}
